<?php

namespace App\Kuafu\Pay\Command;

use App\Kuafu\Base\Model\BaseModel;
use App\Kuafu\CouponExt\Enum\CouponExtEnum;
use App\Kuafu\CouponExt\Model\OrderCouponExtSplitModel;
use App\Kuafu\Order\Enum\CodeEnum;
use App\Kuafu\Order\Model\OrderCouponSplitModel;
use App\Kuafu\Order\Model\OrderPayUnionSplitModel;
use App\Kuafu\Pay\Model\PayStreamModel;
use App\Kuafu\Pay\Model\RefundStreamModel;
use App\Kuafu\WaiMai\Enum\WaiMaiDBEnum;
use App\Kuafu\WaiMai\Model\WaiMaiOrderDetailModel;
use App\Kuafu\WaiMai\Model\WaiMaiOrderModel;
use App\Library\SnowFlake\SnowFlake;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;

class InitPayUnion extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'pay-init-union {shopId?} {date?} {total?}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '初始化支付统计表信息';

    /**
     * Create a new command instance.
     *
     * @return void//
     */
    public function __construct()
    {
        parent::__construct();
    }

    private array $shopIds   = [];
    private int   $now;
    private int   $startTime = 0;
    private int   $endTime   = 0;

    /**
     * Execute the console command
     *
     * @return int
     */
    public function handle()
    {
        ini_set('memory_limit', '-1');

        $date      = $this->argument('date') ?? date("Ymd", strtotime("-1 day"));
        $total     = $this->argument('total') ?? 0;
        $argShopId = $this->argument('shopId') ?? 0;

        if ($total) {
            $this->startTime = 0;
            $this->endTime   = strtotime(date('Ymd'));
        } else {
            $this->startTime = strtotime($date);
            $this->endTime   = $this->startTime + 86400 - 1;
        }

//        dd($this->startTime,$this->endTime)

        dump("InitPayUnion Start: shopId:{$argShopId} date:{$date} total:{$total}");
        Log::info("InitPayUnion Start: shopId:{$argShopId} date:{$date} total:{$total}");
        sleep(1);

        $this->now = time();

        // 清空现有表
        if ($argShopId) {
            OrderPayUnionSplitModel::suffix($argShopId)
                                   ->where('shopId', $argShopId)
                                   ->when(!$total, function ($query) {
                                       $query->whereBetween('createdAt', [$this->startTime, $this->endTime]);
                                   })
                                   ->delete();
        } else {
            for ($i = 0; $i <= 99; $i++) {
                if ($total) {
                    OrderPayUnionSplitModel::suffix($i)
                                           ->truncate();
                    dump("truncate OrderPayUnionSplitModel Finish {$i}...");
                } else {
                    OrderPayUnionSplitModel::suffix($i)
                                           ->whereBetween('createdAt', [$this->startTime, $this->endTime])
                                           ->delete();
                    dump("delete OrderPayUnionSplitModel Finish {$i}...");

                    // 循环delete压力太大了
                    sleep(1);
                }
            }
        }

        // 支付流水
        $shopIds = [];

        // 找到所有的shopIds
        for ($i = 0; $i < 100; $i++) {

            $shopIds = array_merge($shopIds, PayStreamModel::suffix($i)
                                                           ->when($this->startTime, function ($query) {
                                                               $query->whereBetween('createdAt',
                                                                   [$this->startTime, $this->endTime]);
                                                           })
                                                           ->when($argShopId, function ($query) use ($argShopId) {
                                                               $query->where('shopId', $argShopId);
                                                           })
                                                           ->whereIn('sysType', PayStreamModel::SYS_TYPE_PAY_IN_APP)
                                                           ->groupBy('shopId')
                                                           ->pluck('shopId')
                                                           ->toArray());
        }

        foreach ($shopIds as $shopId) {
            $this->shopIds[$shopId] = 1;

            PayStreamModel::suffix($shopId)
                          ->where('shopId', $shopId)
                          ->where('payStatus', PayStreamModel::PAY_STATUS_1)
                          ->where('isPaidIn', PayStreamModel::PAID_IN_YES)
                          ->where('payPrice', '>', 0)
                          ->when($this->startTime, function ($query) {
                              $query->whereBetween('createdAt', [$this->startTime, $this->endTime]);
                          })
                          ->chunk(500, function ($pays) use ($shopId) {

                              $pays->each(function ($item) use ($shopId) {
                                  // 富有 & 自定义支付 & 现金
                                  switch ($item->payChannel) {
                                      case PayStreamModel::PAY_CHANNEL_FY:
                                          $childType     = $item->payChannelChild;
                                          $childTypeDesc = PayStreamModel::PAY_CHANNEL_CHILD_TEXT[$item->payChannelChild] ?? '未知渠道';
                                          break;
                                      default:
                                          $childType     = $item->payChannel > PayStreamModel::PAY_CHANNEL_CUSTOM_PAYMENT ? $item->payChannel : 0;
                                          $childTypeDesc = $item->payChannel > PayStreamModel::PAY_CHANNEL_CUSTOM_PAYMENT ? ($item->streamCustomPaymentRel ? $item->streamCustomPaymentRel->name : "") : "";
                                          break;
                                  }

                                  $data = [
                                      'shopId'            => $shopId,
                                      'orderId'           => $item->orderId,
                                      'bizId'             => $item->payNo,
                                      'payType'           => OrderPayUnionSplitModel::getPayTypeByPayChannel($item->payChannel),
                                      'childType'         => $childType,
                                      'childTypeDesc'     => $childTypeDesc,
                                      'payPrice'          => $item->payPrice,
                                      'payStatus'         => OrderPayUnionSplitModel::PAY_STATUS_OK,
                                      'createdAt'         => $item->createdAt->timestamp,
                                      'originalCreatedAt' => time(),
                                      'originalPrice'     => 0,
                                  ];

                                  $this->addZSort($data);
                              });
                          });
            dump("PayStream Finish {$shopId}...");
        }

        // 退款流水
        RefundStreamModel::query()
                         ->when($this->startTime, function ($query) {
                             $query->whereBetween('createdAt', [$this->startTime, $this->endTime]);
                         })
                         ->when($argShopId, function ($query) use ($argShopId) {
                             $query->where('shopId', $argShopId);
                         })
                         ->whereIn('sysType', PayStreamModel::SYS_TYPE_PAY_IN_APP)
                         ->groupBy('shopId')
                         ->pluck('shopId')
                         ->each(function ($shopId) {

                             $this->shopIds[$shopId] = 1;

                             (new BaseModel())->setSplitShopId($shopId);
                             RefundStreamModel::query()
                                              ->with('payStreamRel')
                                              ->where('shopId', $shopId)
                                              ->when($this->startTime, function ($query) {
                                                  $query->whereBetween('createdAt', [$this->startTime, $this->endTime]);
                                              })
                                              ->where('refundStatus', RefundStreamModel::REFUND_STATUS_OK)
                                              ->where('refundPrice', '>', 0)
                                              ->chunk(500, function ($pays) use ($shopId) {

                                                  $pays->each(function ($item) use ($shopId) {
                                                      $isPaidIn = (int)optional($item->payStreamRel)->isPaidIn;

                                                      // 只要计入实收的流水
                                                      if (!$isPaidIn) {
                                                          return;
                                                      }

                                                      // 富有 & 自定义支付 & 现金
                                                      switch ($item->refundChannel) {
                                                          case PayStreamModel::PAY_CHANNEL_FY:
                                                              $childType     = $item->refundChannelChild;
                                                              $childTypeDesc = PayStreamModel::PAY_CHANNEL_CHILD_TEXT[$item->refundChannelChild] ?? '未知渠道';;
                                                              break;
                                                          default:
                                                              $childType     = $item->refundChannel > PayStreamModel::PAY_CHANNEL_CUSTOM_PAYMENT ? $item->refundChannel : 0;
                                                              $childTypeDesc = $item->refundChannel > PayStreamModel::PAY_CHANNEL_CUSTOM_PAYMENT ? ($item->streamCustomPaymentRel ? $item->streamCustomPaymentRel->name : "") : "";
                                                              break;
                                                      }

                                                      $data = [
                                                          'shopId'            => $shopId,
                                                          'orderId'           => $item->orderId,
                                                          'bizId'             => $item->refundNo,
                                                          'payType'           => OrderPayUnionSplitModel::getPayTypeByPayChannel($item->refundChannel),
                                                          'childType'         => $childType,
                                                          'childTypeDesc'     => $childTypeDesc,
                                                          'payPrice'          => $item->refundPrice,
                                                          'payStatus'         => OrderPayUnionSplitModel::PAY_STATUS_REFUND,
                                                          'createdAt'         => $item->createdAt->timestamp,
                                                          'originalCreatedAt' => time(),
                                                          'originalPrice'     => 0,
                                                      ];
                                                      $this->addZSort($data);

                                                  });
                                              });
                             dump("RefundStream Finish {$shopId}...");
                         });

        // kf券
        for ($i = 0; $i <= 99; $i++) {
            if ($argShopId && $argShopId % 100 != $i) {
                continue;
            }

            OrderCouponSplitModel::suffix($i)
                                 ->where('status', OrderCouponSplitModel::STATUS_USED)
                                 ->when($this->startTime, function ($query) {
                                     $query->whereBetween('createdAt', [$this->startTime, $this->endTime]);
                                 })
                                 ->when($argShopId, function ($query) use ($argShopId) {
                                     $query->where('shopId', $argShopId);
                                 })
                                 ->chunk(500, function ($pays) use ($i) {
                                     $pays->each(function ($item) use ($i) {
                                         //代金券
                                         $data = [
                                             'shopId'            => $item->shopId,
                                             'orderId'           => $item->orderId,
                                             'bizId'             => $item->id,
                                             'payType'           => OrderPayUnionSplitModel::PAY_TYPE_COUPON_KF,
                                             'childType'         => $item->couponId,
                                             'childTypeDesc'     => $item->couponName,
                                             'payPrice'          => $item->couponCostPrice,
                                             'payStatus'         => OrderPayUnionSplitModel::PAY_STATUS_OK,
                                             'createdAt'         => $item->createdAt,
                                             'originalCreatedAt' => time(),
                                             'originalPrice'     => 0,
                                         ];

                                         $this->shopIds[$item->shopId] = 1;

                                         $this->addZSort($data);
                                     });
                                 });
            dump("OrderCoupon Finish {$i}...");
        }

        // 三方券
        for ($i = 0; $i <= 99; $i++) {
            if ($argShopId && $argShopId % 100 != $i) {
                continue;
            }

            OrderCouponExtSplitModel::suffix($i)
                                    ->where('couponExtStatus', CouponExtEnum::COUPON_STATUS_USED)
                                    ->when($this->startTime, function ($query) {
                                        $query->whereBetween('createdAt', [$this->startTime, $this->endTime]);
                                    })
                                    ->when($argShopId, function ($query) use ($argShopId) {
                                        $query->where('shopId', $argShopId);
                                    })
                                    ->chunk(500, function ($pays) use ($i) {

                                        $pays->each(function ($item) use ($i) {
                                            //第三方券
                                            $data = [
                                                'shopId'            => $item->shopId,
                                                'orderId'           => $item->orderId,
                                                'bizId'             => $item->id,
                                                'payType'           => OrderPayUnionSplitModel::EXT_COUPON_MAP[$item->extPlatform],
                                                'childType'         => $item->couponExtSid,
                                                'childTypeDesc'     => $item->couponExtName,
                                                'payPrice'          => $item->couponExtCostPrice,
                                                'payStatus'         => OrderPayUnionSplitModel::PAY_STATUS_OK,
                                                'createdAt'         => $item->createdAt->timestamp,
                                                'originalCreatedAt' => time(),
                                                'originalPrice'     => 0,
                                            ];

                                            $this->shopIds[$item->shopId] = 1;

                                            $this->addZSort($data);
                                        });
                                    });
            dump("OrderCouponExternal Finish {$i}...");
        }


        // 外卖
        for ($i = 0; $i <= 99; $i++) {
            if ($argShopId && $argShopId % 100 != $i) {
                continue;
            }

            WaiMaiOrderModel::suffix($i)
                            ->where("orderStatus", WaiMaiDBEnum::ORDER_STATUS_5)
                            ->whereIn("sourceType", [
                                WaiMaiDBEnum::SOURCE_TYPE_MT_WM,
                                WaiMaiDBEnum::SOURCE_TYPE_ELM,
                                CodeEnum::SOURCE_TYPE_DY
                            ])
                            ->when($this->startTime, function ($query) {
                                $query->whereBetween('createdAt', [$this->startTime, $this->endTime]);
                            })
                            ->when($argShopId, function ($query) use ($argShopId) {
                                $query->where('shopId', $argShopId);
                            })
                            ->chunk(500, function ($pays) use ($i) {
                                $pays->each(function ($item) use ($i) {
                                    //外卖 ZHE
                                    $data = [
                                        'shopId'            => $item->shopId,
                                        'orderId'           => $item->orderId,
                                        'bizId'             => "",
                                        'payType'           => OrderPayUnionSplitModel::PAY_TYPE_TAKEOUT,
                                        'childType'         => $item->sourceType,
                                        'childTypeDesc'     => CodeEnum::SOURCE_TYPES[$item->sourceType],
                                        'payPrice'          => $item->expectIncome,
                                        'originalPrice'     => $item->originalPrice,
                                        'payStatus'         => OrderPayUnionSplitModel::PAY_STATUS_OK,
                                        'createdAt'         => $item->createdAt->timestamp,
                                        'originalCreatedAt' => time(),
                                    ];

                                    if ($item->refundPrice > 0) {
                                        $refundData = [
                                            'originalPrice'     => 0,
                                            'shopId'            => $item->shopId,
                                            'orderId'           => $item->orderId,
                                            'bizId'             => "",
                                            'payType'           => OrderPayUnionSplitModel::PAY_TYPE_TAKEOUT,
                                            'childType'         => $item->sourceType,
                                            'childTypeDesc'     => CodeEnum::SOURCE_TYPES[$item->sourceType],
                                            'payPrice'          => $item->refundPrice,
                                            'payStatus'         => OrderPayUnionSplitModel::PAY_STATUS_REFUND,
                                            'createdAt'         => $item->createdAt->timestamp,
                                            'originalCreatedAt' => time(),
                                        ];
                                        $this->addZSort($refundData);
                                    }

                                    $this->shopIds[$item->shopId] = 1;
                                    $this->addZSort($data);
                                });
                            });
            dump("WaiMaiOrder Finish {$i}...");
        }

        // 按时间排序，挨个insert
        dump($this->shopIds);
        foreach (array_keys($this->shopIds) as $shopId) {
            if ($shopId == 0) {
                continue;
            }

            $i = 0;
            while (true) {

                $lists = Redis::zrevrange($this->getZSortKey($shopId), $i, $i + 499, true);
                if (!$lists) {
                    $this->delZSort($shopId);
                    dump("ShopId: {$shopId} Finish...");
                    break;
                }

                $insertData = [];
                foreach ($lists as $v => $score) {
                    $insertData[] = array_merge(json_decode($v, true), ['id' => SnowFlake::nextIdCache()]);
                }

                OrderPayUnionSplitModel::suffix($shopId)
                                       ->insert($insertData);
                dump("ShopId: {$shopId} +500");

                $i = $i + 500;
            }
        }
    }

    private function getZSortKey(int $shopId): string
    {
        return "INIT-PAY-UNION:{$this->startTime}-{$this->endTime}:{$shopId}";
    }

    private function addZSort(array $data)
    {
        $key = $this->getZSortKey($data['shopId']);
        Redis::zadd($key, $this->now - $data['createdAt'], json_encode($data));
    }

    private function delZSort(int $shopId)
    {
        $key = $this->getZSortKey($shopId);
        Redis::del($key);
    }

}
